home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-09-08 | 11.9 KB | 325 lines | [TEXT/CCL2] |
- ;;;
- ;;; object-dropper.lisp
- ;;;
-
- #|
- ================================================================
- Purpose ========================================================
- ================================================================
- Defines a extensible object drop functionality.
-
- Generic functions specify the interface.
-
- This program's users must implement their own policy for deciding when a
- drop is initiated (i.e. when track-mouse-for-dropping is called). Some
- possibilities are:
-
- - When an already-selected item is clicked on.
- - When a certain modifier key combination is present (e.g. command-option).
-
-
- ================================================================
- Status =========================================================
- ================================================================
- Released.
-
- Copyright © 1990-92 Matthew Cornell. All Rights Reserved. Send
- bugs, comments, questions, and fixes to cornell@cs.umass.edu.
-
-
- ================================================================
- Change history =================================================
- ================================================================
- 02-Aug-92 mc Created.
- 03-Aug-92 mc Improved demo. Added optimize speed.
- 06-Aug-92 mc Changed macptr-region-global and track-mouse-for-dropping to
- take object and pt-global-starting.
- 15-Aug-92 mc Uncommented example fred-mixin code.
- Moved object-fred-dialog-item hook to
- "object-FDI-drop-glue.lisp" .
- 18-Aug-92 mc Defined and exported invert-inside-gray-frame .
- 08-Sep-92 mc Fixed unmatched ) in example code.
-
- |#
-
-
- (in-package "CCL")
-
- (require "DRAG-GRAY-REGION-LISP" "CCL:UMASS Utils;drag-gray-region-lisp")
-
- (export '(F-CAN-RECEIVE-DROP
- INVERT-DROP-HIGHLIGHT
- RECEIVE-DROP
- MACPTR-REGION-GLOBAL
- TRACK-MOUSE-FOR-DROPPING
- INVERT-INSIDE-GRAY-FRAME))
-
-
- ;;;================================================================
- ;;; Define functions related to receiving drops.
- ;;;================================================================
-
- (defgeneric f-can-receive-drop (view object pt-global)
- (:documentation "Returns non-nil if view can receive-drop object at
- pt-global."))
-
-
- (defmethod f-can-receive-drop ((view simple-view) (object t) (pt-global integer))
- "Returns nil."
- ;;
- nil)
-
-
- (defgeneric invert-drop-highlight (view object pt-global)
- (:documentation "Indicates visually what dropping object might do. It is
- critical that drawing be done in :patXOr mode so that it can be undone
- while tracking. Pt-global is the current mouse position."))
-
-
- (defmethod invert-drop-highlight ((view simple-view) (object t) (pt-global integer))
- ;;
- (error "~S doesn't know how to invert highlights." view))
-
-
- (defgeneric receive-drop (view object pt-global)
- (:documentation "Takes the dropped action on object. Pt-global is the
- mouse position when it was released."))
-
-
- (defmethod receive-drop ((view simple-view) (object t) (pt-global integer))
- ;;
- (error "~S doesn't know how to receive drops." view))
-
-
- ;;;================================================================
- ;;; Define functions related to starting drops.
- ;;;================================================================
-
- (defgeneric macptr-region-global (view object pt-global-starting)
- (:documentation "Returns the region to be used while
- track-mouse-for-dropping is running, which disposes of the region when
- it's through. Object is the object being carried and pt-global-starting
- is the global point the mouse went down at when tracking started."))
-
-
- (defmethod macptr-region-global ((view simple-view)
- (object t)
- (pt-global-starting integer))
- "Returns a rectangular region that matches view's size and position."
- (declare (optimize speed)
- (ignore pt-global-starting))
- ;;
- (let* ((macptr-region-global (#_NewRgn))
- (pt-top-left (local-to-global view 0))
- (pt-bottom-right (local-to-global view (view-size view))))
- (rlet ((rect :rect :topLeft pt-top-left :bottomRight pt-bottom-right))
- (#_RectRgn macptr-region-global rect)
- macptr-region-global)))
-
-
- (defgeneric track-mouse-for-dropping (view-starting object pt-global-starting
- &key cursor)
- (:documentation "Initiates mouse tracking from view-starting. The loop
- 'carries' object by calling invert-drop-highlight on views that
- f-can-receive-drop. If the mouse is released over one that can, then
- receive-drop is called on it. Pt-global-starting is the global point the
- mouse went down at when tracking started. Cursor is a macptr of a cursor
- used during tracking, and defaults to *arrow-cursor*. Returns the view
- dropped on."))
-
-
- (defmethod track-mouse-for-dropping ((view-starting simple-view)
- (object t)
- (pt-global-starting integer)
- &key (cursor *arrow-cursor*))
- (declare (optimize speed))
- ;;
- (let* ((macptr-region-global
- (macptr-region-global view-starting object pt-global-starting))
- (pt-global-last (view-mouse-position nil))
- (view-last nil)
- (view-current (find-view-containing-point nil pt-global-last)))
- ;;
- ;; Should not call f-can-receive-drop, invert-drop-highlight, or
- ;; invert-drop-highlight on view-starting. Fix!
- ;;
- (drag-gray-region-lisp
- macptr-region-global
- #'(lambda (pt-global-current)
- (setf view-current (find-view-containing-point nil pt-global-current))
- ;;
- ;; There are two interesting cases. (In either case we aren't
- ;; interested in moving into or out of view-start.)
- ;;
- ;; - The mouse moved out of view-last.
- ;; - The mouse moved into view-current.
- ;;
- ;; Invert (dehighlight) the old.
- (when (and view-last
- (neq view-last view-starting)
- (f-can-receive-drop view-last object pt-global-last))
- (invert-drop-highlight view-last object pt-global-last))
- ;; Invert (highlight) the new.
- (when (and view-current
- (neq view-current view-starting)
- (f-can-receive-drop view-current object pt-global-current))
- (invert-drop-highlight view-current object pt-global-current))
- ;;
- (setf pt-global-last pt-global-current
- view-last view-current))
- pt-global-last
- :cursor cursor)
- ;; Dispose, and invert last and call receive-drop on view-last, if it
- ;; wasn't view-starting.
- (#_DisposeRgn macptr-region-global)
- (when (and view-last
- (neq view-last view-starting)
- (f-can-receive-drop view-last object pt-global-last))
- (invert-drop-highlight view-last object pt-global-last)
- (receive-drop view-last object pt-global-last))))
-
-
- (unless (fboundp 'local-to-global)
- ;; From "quickdraw.lisp" :
- (defmethod local-to-global ((view simple-view) h &optional v)
- (with-focused-view view
- (rlet ((p :point))
- (%put-long p (make-point h v))
- (#_LocalToGlobal p)
- (%get-long p)))))
-
- ;;;================================================================
- ;;; Tell fred-mixins how to receive drops.
- ;;;================================================================
-
- (defmethod f-can-receive-drop ((view fred-mixin) (object t) (pt-global integer))
- (declare (ignore object))
- ;;
- (fred-point-position view (global-to-local view pt-global)))
-
-
- (unless (fboundp 'global-to-local)
- ;; From "quickdraw.lisp" :
- (defmethod global-to-local ((view simple-view) h &optional v)
- (with-focused-view view
- (rlet ((p :point))
- (%put-long p (make-point h v))
- (#_GlobalToLocal p)
- (%get-long p)))))
-
-
- (defmethod invert-drop-highlight ((view fred-mixin) (object t) (pt-global integer))
- "Invert a vertical bar at view's buffer position corresponding to
- pt-global."
- ;;
- (let* ((int-index (fred-point-position view (global-to-local view pt-global)))
- (int-pos-horizontal-bottom (fred-hpos view int-index))
- (int-pos-vertical (fred-vpos view int-index))
- (int-height-line (- (fred-line-vpos view 1)
- (fred-line-vpos view 0))))
- (with-focused-view view
- (with-pen-saved
- (#_PenMode (position :PATXOR *pen-modes*))
- ;; #_PenPat Needed only for object-fred-dialog-items, which
- ;; inverted in *gray-pattern* (fred-mixins worked fine):
- (#_PenPat *black-pattern*)
- (#_MoveTo int-pos-horizontal-bottom int-pos-vertical)
- (#_Line 0 (- int-height-line))))))
-
-
- (defmethod receive-drop ((view fred-mixin) (object t) (pt-global integer))
- ;;
- (ed-insert-with-undo view (format nil "~A" object)
- (fred-point-position view (global-to-local view pt-global)))
- (fred-update view))
-
-
- ;;;================================================================
- ;;; Define some handy drop-highlight functions.
- ;;;================================================================
-
- (defmethod invert-inside-gray-frame ((view simple-view))
- "Inverts a gray frame just inside view. (Headache if it's thick!)"
- (declare (optimize speed))
- ;;
- (let* ((pt-top-left #@(0 0))
- (pt-bottom-right (view-size view)))
- (rlet ((rect :rect :topLeft pt-top-left :bottomRight pt-bottom-right))
- (with-focused-view view
- (with-pen-saved
- (#_PenMode (position :PATXOR *pen-modes*))
- (#_PenPat *gray-pattern*)
- (#_PenSize 3 3)
- (#_FrameRect rect))))))
-
-
- ;;;================================================================
- ;;; Done.
- ;;;================================================================
-
- (provide "OBJECT-DROPPER")
-
-
- #|
- ;;; See object-FDI-drop-glue.lisp for another example.
-
- ;;; Define sample code.
-
- ;;;
- ;;; Make items that can start and receive drops.
- ;;;
-
- (defclass receive-button-dialog-item (button-dialog-item)
- ((sym-function
- :accessor sym-function-rbdi
- :initarg :sym-function
- :initform 'describe
- :type symbol
- :documentation "A symbol with a function definition. The definition is
- run by receive-drop on the object dropped."))
- (:documentation "Runs sym-function-rbdi on dropped items."))
-
- (defmethod initialize-instance :after ((receive-button-dialog-item receive-button-dialog-item)
- &key dialog-item-text)
- (unless dialog-item-text
- (set-dialog-item-text
- receive-button-dialog-item
- (format nil "~:(~A~)" (sym-function-rbdi receive-button-dialog-item)))))
-
- (defmethod f-can-receive-drop ((view receive-button-dialog-item) (object t) (pt-global integer))
- t)
-
- (defmethod invert-drop-highlight ((view receive-button-dialog-item) (object t) (pt-global integer))
- ;; Invert a gray frame just inside view. (Headache if it's thick!)
- (invert-inside-gray-frame view))
-
-
- (defmethod receive-drop ((view receive-button-dialog-item) (object t) (pt-global integer))
- (funcall (symbol-function (sym-function-rbdi view))
- object))
-
-
- (defun test-dropper ()
- (let* ((window (make-instance 'window
- :window-title "Test Dropper"
- :view-position #@(475 41)
- :view-size #@(169 58)))
- (start-dialog-item (make-instance 'button-dialog-item
- :view-size #@(80 20)
- :view-position #@(5 5)
- :view-font '("Geneva" 9)
- :dialog-item-text "Start Tracking"))
- (receive-dialog-item (make-instance 'receive-button-dialog-item
- :view-size #@(80 20)
- :view-position #@(20 30)
- :view-font '("Geneva" 9))))
- (add-subviews window start-dialog-item receive-dialog-item)
- ;;
- (defmethod view-click-event-handler ((view (eql start-dialog-item))
- where)
- ;;
- (track-mouse-for-dropping
- view view (local-to-global (view-container view) where)))
- window))
-
- |#